/*
 * @Author: 0x9DEFA478
 * @Date: 2022-06-21 21:25:00
 * @LastEditTime: 2022-06-25 23:09:25
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#include "IP_SDMMC_SD.h"
#include "System/System.h"
#include "H_Memory.h"




static int ConfigCmd(IP_SDMMC_SD* ip_sdmmc_sd,IP_SDMMC_SD_CmdParam* Param){
  unsigned int CMD;

  ip_sdmmc_sd->CmdParam=Param[0];

  CMD=(((unsigned int)Param->Send.Command)<<SDMMC_CMD_CMDINDEX_Pos)&SDMMC_CMD_CMDINDEX_Msk;

  switch(Param->Respond.Type){
    case vIP_SDMMC_SD_CmdParam_RespondType_Short:
      CMD|=(0x1U<<SDMMC_CMD_WAITRESP_Pos)&SDMMC_CMD_WAITRESP_Msk;
      break;
    case vIP_SDMMC_SD_CmdParam_RespondType_Long:
      CMD|=(0x3U<<SDMMC_CMD_WAITRESP_Pos)&SDMMC_CMD_WAITRESP_Msk;
      break;
    case vIP_SDMMC_SD_CmdParam_RespondType_None:
      break;
    default:
      return -2;
  }

  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ARG=Param->Send.Argument;
  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->CMD=CMD;

  return 0;
}

static int ConfigData(IP_SDMMC_SD* ip_sdmmc_sd,IP_SDMMC_SD_DataParam* Param){
  unsigned int DCTRL;
  unsigned int BlockSize;
  unsigned int blockSize;
  unsigned int DBLOCKSIZE;
  unsigned int Length;
  unsigned char* LastBuffer;
  int LastLength;
  unsigned int TransferSize;


  ip_sdmmc_sd->DataParam=Param[0];

  DCTRL=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DCTRL;

  if(Param->Data.IsTransmit==0){
    DCTRL|=SDMMC_DCTRL_DTDIR;          //卡到控制器
  }else{
    DCTRL&=(~SDMMC_DCTRL_DTDIR);       //控制器到卡
  }

  BlockSize=Param->Data.BlockSize;
  if(ip_sdmmc_sd->BlockSize!=BlockSize){
    ip_sdmmc_sd->BlockSize=BlockSize;

    if(BlockSize<=0){
      DCTRL|=SDMMC_DCTRL_DTMODE;
    }else{
      DBLOCKSIZE=0;

      blockSize=BlockSize;
      while(((blockSize&0x00000001U)==0U)&&(DBLOCKSIZE<15)){
        DBLOCKSIZE++;
        blockSize>>=1;
      }

      if((1U<<DBLOCKSIZE)!=BlockSize){
        return -2;
      }

      DCTRL=(DCTRL&(~(SDMMC_DCTRL_DTMODE|SDMMC_DCTRL_DBLOCKSIZE_Msk)))|((DBLOCKSIZE<<SDMMC_DCTRL_DBLOCKSIZE_Pos)&SDMMC_DCTRL_DBLOCKSIZE_Msk);
    }

  }


  LastBuffer=Param->Data.Buffer;
  LastLength=Param->Data.Length;

  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DTIMER=Param->Data.TimeoutClk;
  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DLEN=(unsigned int)LastLength;

  if(Param->Data.IsTransmit!=0){
    TransferSize=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABSIZE;

    Length=(LastLength<TransferSize)?LastLength:TransferSize;
    H_MemoryCopy_byte((void*)cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABASE0,LastBuffer,Length);
    LastBuffer=&LastBuffer[Length];
    LastLength-=Length;

    if(LastLength>0){
      Length=(LastLength<TransferSize)?LastLength:TransferSize;
      H_MemoryCopy_byte((void*)cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABASE1,LastBuffer,Length);
      LastBuffer=&LastBuffer[Length];
      LastLength-=Length;
    }
    System_DataMemoryBarrier();
  }

  ip_sdmmc_sd->IsOdd=0;
  ip_sdmmc_sd->LastBuffer=LastBuffer;
  ip_sdmmc_sd->LastLength=LastLength;

  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DCTRL=DCTRL;

  return 0;
}




/**
 * @brief 进行SDMMC指令响应通信
 * @param ip_sdmmc_sd IP_SDMMC_SD对象
 * @param Param 通信参数
 * @return 0:通信发起成功 其他:通信发起失败
 */
int IP_SDMMC_SD_CmdCommunication(IP_SDMMC_SD* ip_sdmmc_sd,IP_SDMMC_SD_CmdParam* Param){
  int r;

  if(ip_sdmmc_sd->CommandIsBusy!=0){
    return -1;
  }

  r=ConfigCmd(ip_sdmmc_sd,Param);
  if(r!=0){
    return r;
  }

  ip_sdmmc_sd->CommandIsBusy=-1;
  
  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->CMD|=SDMMC_CMD_CPSMEN;//启动传输

  return 0;
}

/**
 * @brief 进行SDMMC数据通信
 * @param ip_sdmmc_sd IP_SDMMC_SD对象
 * @param Param 通信参数
 * @return 0:通信发起成功 其他:通信发起失败
 */
int IP_SDMMC_SD_DataCommunication(IP_SDMMC_SD* ip_sdmmc_sd,IP_SDMMC_SD_DataParam* Param){
  int r;

  if(ip_sdmmc_sd->DataIsBusy!=0){
    return -1;
  }

  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DCTRL|=SDMMC_DCTRL_FIFORST;

  r=ConfigData(ip_sdmmc_sd,Param);
  if(r!=0){
    return r;
  }

  ip_sdmmc_sd->DataIsBusy=-1;

  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMACTRL=SDMMC_IDMA_IDMABMODE|SDMMC_IDMA_IDMAEN;
  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DCTRL|=SDMMC_DCTRL_DTEN;//使能传输

  return 0;
}

/**
 * @brief 进行SDMMC指令响应并传输数据通信 Cmd与Data同时触发
 * @param ip_sdmmc_sd IP_SDMMC_SD对象
 * @param CmdParam 命令通信参数
 * @param DataParam 数据通信参数
 * @return 0:通信发起成功 其他:通信发起失败
 */
int IP_SDMMC_SD_CmdDataCommunication(IP_SDMMC_SD* ip_sdmmc_sd,IP_SDMMC_SD_CmdParam* CmdParam,IP_SDMMC_SD_DataParam* DataParam){
  int r;

  if((ip_sdmmc_sd->CommandIsBusy!=0)||(ip_sdmmc_sd->DataIsBusy!=0)){

    return -1;
  }

  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->DCTRL|=SDMMC_DCTRL_FIFORST;

  r=ConfigCmd(ip_sdmmc_sd,CmdParam);
  if(r!=0){
    return r;
  }
  r=ConfigData(ip_sdmmc_sd,DataParam);
  if(r!=0){
    return r;
  }
  
  ip_sdmmc_sd->CommandIsBusy=-1;
  ip_sdmmc_sd->DataIsBusy=-1;
  
  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMACTRL=SDMMC_IDMA_IDMABMODE|SDMMC_IDMA_IDMAEN;
  cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->CMD|=SDMMC_CMD_CMDTRANS|SDMMC_CMD_CPSMEN;//启动传输

  return 0;
}




void IP_SDMMC_SD_IRQ(void* v){
  IP_SDMMC_SD* ip_sdmmc_sd;
  IP_SDMMC_SD_RespondDoneParam RespondDoneParam;
  unsigned int STA;
  
  void* Buffer;
  unsigned int Length;
  unsigned char* LastBuffer;
  int LastLength;
  unsigned int TransferSize;

  ip_sdmmc_sd=v;

  STA=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->STA;

  if((STA&SDMMC_STA_IDMABTC)!=0U){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_IDMABTCC;

    LastLength=ip_sdmmc_sd->LastLength;
    if(LastLength>0){
      //还有需要操作的数据

      //判断空闲的缓存区
      if(ip_sdmmc_sd->IsOdd==0U){
        ip_sdmmc_sd->IsOdd=-1;
        Buffer=(void*)cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABASE0;
      }else{
        ip_sdmmc_sd->IsOdd=0;
        Buffer=(void*)cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABASE1;
      }
      LastBuffer=ip_sdmmc_sd->LastBuffer;
      TransferSize=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABSIZE;
      Length=(LastLength<TransferSize)?LastLength:TransferSize;

      if(ip_sdmmc_sd->DataParam.Data.IsTransmit==0){
        
        System_DataMemoryBarrier();

        //读取数据
        H_MemoryCopy_byte(LastBuffer,Buffer,Length);
      }else{

        //写入数据
        H_MemoryCopy_byte(Buffer,LastBuffer,Length);
        
        System_DataMemoryBarrier();
      }
      LastBuffer=&LastBuffer[Length];
      LastLength-=Length;
        
      ip_sdmmc_sd->LastBuffer=LastBuffer;
      ip_sdmmc_sd->LastLength=LastLength;
    }

  }else if((STA&SDMMC_STA_IDMATE)!=0U){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_IDMATEC;
  }

  if((STA&SDMMC_STA_CMDSENT)!=0U){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_CMDSENTC;

    //命令发送完成处理
    if(ip_sdmmc_sd->CommandIsBusy!=0){
      if(ip_sdmmc_sd->CmdParam.Respond.Type==vIP_SDMMC_SD_CmdParam_RespondType_None){
        ip_sdmmc_sd->CommandIsBusy=0;
      }
      ip_sdmmc_sd->CmdParam.Callback.SendDone(ip_sdmmc_sd->CmdParam.Callback.v);
    }
  }

  if((STA&SDMMC_STA_CMDREND)!=0U){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_CMDRENDC;

    //响应接收完成处理
    if(ip_sdmmc_sd->CommandIsBusy!=0){
      ip_sdmmc_sd->CommandIsBusy=0;

      ip_sdmmc_sd->CmdParam.Callback.SendDone(ip_sdmmc_sd->CmdParam.Callback.v);

      RespondDoneParam.Result=vIP_SDMMC_SD_CmdRespondDone_Result_Ok;
      RespondDoneParam.Respond.Command=(cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESPCMD&SDMMC_RESPCMD_RESPCMD_Msk)>>SDMMC_RESPCMD_RESPCMD_Pos;
      RespondDoneParam.Respond.CardStatus[0]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP1;
      RespondDoneParam.Respond.CardStatus[1]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP2;
      RespondDoneParam.Respond.CardStatus[2]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP3;
      RespondDoneParam.Respond.CardStatus[3]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP4;
      ip_sdmmc_sd->CmdParam.Callback.RespondDone(ip_sdmmc_sd->CmdParam.Callback.v,&RespondDoneParam);
    }

  }else if((STA&SDMMC_STA_CTIMEOUT)!=0U){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_CTIMEOUTC;

    //超时
    if(ip_sdmmc_sd->CommandIsBusy!=0){
      ip_sdmmc_sd->CommandIsBusy=0;

      ip_sdmmc_sd->CmdParam.Callback.SendDone(ip_sdmmc_sd->CmdParam.Callback.v);

      RespondDoneParam.Result=vIP_SDMMC_SD_CmdRespondDone_Result_Timeout;
      ip_sdmmc_sd->CmdParam.Callback.RespondDone(ip_sdmmc_sd->CmdParam.Callback.v,&RespondDoneParam);
    }

  }else if((STA&SDMMC_STA_CCRCFAIL)!=0U){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_CCRCFAILC;

    //CRC错误
    if(ip_sdmmc_sd->CommandIsBusy!=0){
      ip_sdmmc_sd->CommandIsBusy=0;

      ip_sdmmc_sd->CmdParam.Callback.SendDone(ip_sdmmc_sd->CmdParam.Callback.v);

      RespondDoneParam.Result=vIP_SDMMC_SD_CmdRespondDone_Result_Error;
      RespondDoneParam.Respond.Command=(cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESPCMD&SDMMC_RESPCMD_RESPCMD_Msk)>>SDMMC_RESPCMD_RESPCMD_Pos;
      RespondDoneParam.Respond.CardStatus[0]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP1;
      RespondDoneParam.Respond.CardStatus[1]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP2;
      RespondDoneParam.Respond.CardStatus[2]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP3;
      RespondDoneParam.Respond.CardStatus[3]=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->RESP4;
      ip_sdmmc_sd->CmdParam.Callback.RespondDone(ip_sdmmc_sd->CmdParam.Callback.v,&RespondDoneParam);
    }

  }




  if(STA&SDMMC_STA_DATAEND){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_DATAENDC;

    //数据传输成功
    if(ip_sdmmc_sd->DataIsBusy!=0){
      ip_sdmmc_sd->DataIsBusy=0;

      LastLength=ip_sdmmc_sd->LastLength;
      if(LastLength>0){
        //还有需要操作的数据

        //判断空闲的缓存区
        if(ip_sdmmc_sd->IsOdd==0U){
          ip_sdmmc_sd->IsOdd=-1;
          Buffer=(void*)cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABASE0;
        }else{
          ip_sdmmc_sd->IsOdd=0;
          Buffer=(void*)cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABASE1;
        }
        LastBuffer=ip_sdmmc_sd->LastBuffer;
        TransferSize=cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMABSIZE;
        Length=(LastLength<TransferSize)?LastLength:TransferSize;

        if(ip_sdmmc_sd->DataParam.Data.IsTransmit==0){
          
          System_DataMemoryBarrier();

          //读取数据
          H_MemoryCopy_byte(LastBuffer,Buffer,Length);
        }else{

          //写入数据
          H_MemoryCopy_byte(Buffer,LastBuffer,Length);
          
          System_DataMemoryBarrier();
        }
        LastBuffer=&LastBuffer[Length];
        LastLength-=Length;
          
        ip_sdmmc_sd->LastBuffer=LastBuffer;
        ip_sdmmc_sd->LastLength=LastLength;
      }

      ip_sdmmc_sd->DataParam.Callback.Done(ip_sdmmc_sd->DataParam.Callback.v,vIP_SDMMC_SD_DataDone_Result_Ok);
    }

    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMACTRL=0U;

  }else if(STA&SDMMC_STA_DTIMEOUT){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_DTIMEOUTC;

    //数据传输超时
    if(ip_sdmmc_sd->DataIsBusy!=0){
      ip_sdmmc_sd->DataIsBusy=0;

      ip_sdmmc_sd->DataParam.Callback.Done(ip_sdmmc_sd->DataParam.Callback.v,vIP_SDMMC_SD_DataDone_Result_Timeout);
    }

    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMACTRL=0U;

  }else if(STA&SDMMC_STA_DCRCFAIL){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=SDMMC_ICR_DCRCFAILC;

    //CRC错误
    if(ip_sdmmc_sd->DataIsBusy!=0){
      ip_sdmmc_sd->DataIsBusy=0;
      
      ip_sdmmc_sd->DataParam.Callback.Done(ip_sdmmc_sd->DataParam.Callback.v,vIP_SDMMC_SD_DataDone_Result_Error);
    }

    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMACTRL=0U;

  }else if(STA&(SDMMC_STA_TXUNDERR&SDMMC_STA_RXOVERR)){
    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->ICR=(SDMMC_STA_TXUNDERR&SDMMC_STA_RXOVERR);

    //FIFO错误
    if(ip_sdmmc_sd->DataIsBusy!=0){
      ip_sdmmc_sd->DataIsBusy=0;
      
      ip_sdmmc_sd->DataParam.Callback.Done(ip_sdmmc_sd->DataParam.Callback.v,vIP_SDMMC_SD_DataDone_Result_Error);
    }

    cIP_SDMMC_SD_SDMMC(ip_sdmmc_sd)->IDMACTRL=0U;

  }


}



